#include <System.h>
#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

using namespace boost;
using tcp = asio::ip::tcp;

using namespace sys;

class chat_client {
private:
    asio::io_context& io_context;
    tcp::socket       socket;
    std::vector<char> read_msg_;

public:
    chat_client(asio::io_context& io_context, const tcp::resolver::results_type& endpoints)
        : io_context(io_context),
          socket(io_context) {
        read_msg_.resize(1024);
        do_connect(endpoints);
    }
    ~chat_client() {}

public:
    void write(std::string msg) {
        boost::asio::post(io_context,
            [this, msg]() {
                do_write(msg);
            });
    }

    void close() {
    }

private:
    void do_write(std::string msg) {
        boost::asio::async_write(socket,
            boost::asio::buffer(msg.data(),
                msg.size()),
            [this](boost::system::error_code ec, std::size_t /*length*/) {
                if (!ec) {
                }
                else {
                    socket.close();
                }
            });
    }
    void do_connect(const tcp::resolver::results_type& endpoints) {
        boost::asio::async_connect(socket, endpoints,
            [this](boost::system::error_code ec, tcp::endpoint) {
                if (!ec) {
                    do_read();
                }
                else {
                    System::err << ec.what() << std::endl;
                }
            });
    }
    void do_read() {
        boost::asio::async_read(socket,
            boost::asio::buffer(read_msg_.data(), read_msg_.size()),
            [this](boost::system::error_code ec, std::size_t len /*length*/) {
                if (!ec) {
                    System::out << "read:" << len << ":" << std::string(this->read_msg_.data(), this->read_msg_.size()) << std::endl;
                    do_read();
                }
                else {
                    System::err << ec.what() << std::endl;
                }
            });
    }
};

int main(int argc, char const* argv[]) {
    asio::io_context io_context;
    tcp::resolver    resolver(io_context);

    auto        endpoints = resolver.resolve("127.0.0.1", "4090");
    chat_client c(io_context, endpoints);

    std::thread t([&io_context]() { io_context.run(); });

    std::vector<char> line;
    line.resize(1024);
    memset(line.data(), 0, line.size());

    while (std::cin.getline(line.data(), line.size())) {
        std::string msg(line.data());
        System::out << msg << std::endl;
        c.write(msg);
        memset(line.data(), 0, line.size());
    }

    c.close();
    t.join();

    return 0;
}
